home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1994 David I. Bell
- * Permission is granted to use, distribute, or modify this source,
- * provided that this copyright notice remains intact.
- *
- * Extended precision rational arithmetic non-primitive functions
- */
-
- #include "qmath.h"
-
-
- NUMBER *_epsilon_; /* default precision for real functions */
- long _epsilonprec_; /* bits of precision for epsilon */
-
-
- /*
- * Set the default precision for real calculations.
- * The precision must be between zero and one.
- */
- void
- setepsilon(q)
- NUMBER *q; /* number to be set as the new epsilon */
- {
- NUMBER *old;
-
- if (qisneg(q) || qiszero(q) || (qreli(q, 1L) >= 0))
- math_error("Epsilon value must be between zero and one");
- old = _epsilon_;
- _epsilonprec_ = qprecision(q);
- _epsilon_ = qlink(q);
- if (old)
- qfree(old);
- }
-
-
- /*
- * Return the inverse of one number modulo another.
- * That is, find x such that:
- * Ax = 1 (mod B)
- * Returns zero if the numbers are not relatively prime (temporary hack).
- */
- NUMBER *
- qminv(q1, q2)
- NUMBER *q1, *q2;
- {
- NUMBER *r;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for minv");
- r = qalloc();
- if (zmodinv(q1->num, q2->num, &r->num)) {
- qfree(r);
- return qlink(&_qzero_);
- }
- return r;
- }
-
-
- /*
- * Return the residue modulo an integer (q3) of an integer (q1)
- * raised to a positive integer (q2) power.
- */
- NUMBER *
- qpowermod(q1, q2, q3)
- NUMBER *q1, *q2, *q3;
- {
- NUMBER *r, *t;
- BOOL s;
-
- if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
- math_error("Non-integers for pmod");
- if (qisneg(q2))
- math_error("Negative power for pmod");
- if (qiszero(q3)) return qpowi(q1, q2);
- s = q3->num.sign;
- q3->num.sign = 0;
- r = qalloc();
- zpowermod(q1->num, q2->num, q3->num, &r->num);
- if (!s || qiszero(r)) return r;
- q3->num.sign = 1;
- t = qadd(r, q3);
- qfree(r);
- return t;
- }
-
-
- /*
- * Return the power function of one number with another.
- * The power must be integral.
- * q3 = qpowi(q1, q2);
- */
- NUMBER *
- qpowi(q1, q2)
- NUMBER *q1, *q2;
- {
- register NUMBER *r;
- BOOL invert, sign;
- ZVALUE num, den, z2;
-
- if (qisfrac(q2))
- math_error("Raising number to fractional power");
- num = q1->num;
- den = q1->den;
- z2 = q2->num;
- sign = (num.sign && zisodd(z2));
- invert = z2.sign;
- num.sign = 0;
- z2.sign = 0;
- /*
- * Check for trivial cases first.
- */
- if (ziszero(num) && !ziszero(z2)) { /* zero raised to a power */
- if (invert)
- math_error("Zero raised to negative power");
- return qlink(&_qzero_);
- }
- if (zisunit(num) && zisunit(den)) { /* 1 or -1 raised to a power */
- r = (sign ? q1 : &_qone_);
- r->links++;
- return r;
- }
- if (ziszero(z2)) /* raising to zeroth power */
- return qlink(&_qone_);
- if (zisunit(z2)) { /* raising to power 1 or -1 */
- if (invert)
- return qinv(q1);
- return qlink(q1);
- }
- /*
- * Not a trivial case. Do the real work.
- */
- r = qalloc();
- if (!zisunit(num))
- zpowi(num, z2, &r->num);
- if (!zisunit(den))
- zpowi(den, z2, &r->den);
- if (invert) {
- z2 = r->num;
- r->num = r->den;
- r->den = z2;
- }
- r->num.sign = sign;
- return r;
- }
-
-
- /*
- * Given the legs of a right triangle, compute its hypothenuse within
- * the specified error. This is sqrt(a^2 + b^2).
- */
- NUMBER *
- qhypot(q1, q2, epsilon)
- NUMBER *q1, *q2, *epsilon;
- {
- NUMBER *tmp1, *tmp2, *tmp3;
-
- if (qisneg(epsilon) || qiszero(epsilon))
- math_error("Bad epsilon value for hypot");
- if (qiszero(q1))
- return qabs(q2);
- if (qiszero(q2))
- return qabs(q1);
- tmp1 = qsquare(q1);
- tmp2 = qsquare(q2);
- tmp3 = qadd(tmp1, tmp2);
- qfree(tmp1);
- qfree(tmp2);
- tmp1 = qsqrt(tmp3, epsilon);
- qfree(tmp3);
- return tmp1;
- }
-
-
- /*
- * Given one leg of a right triangle with unit hypothenuse, calculate
- * the other leg within the specified error. This is sqrt(1 - a^2).
- * If the wantneg flag is nonzero, then negative square root is returned.
- */
- NUMBER *
- qlegtoleg(q, epsilon, wantneg)
- NUMBER *q, *epsilon;
- BOOL wantneg;
- {
- NUMBER *res, *qtmp1, *qtmp2;
- ZVALUE num;
-
- if (qisneg(epsilon) || qiszero(epsilon))
- math_error("Bad epsilon value for legtoleg");
- if (qisunit(q))
- return qlink(&_qzero_);
- if (qiszero(q)) {
- if (wantneg)
- return qlink(&_qnegone_);
- return qlink(&_qone_);
- }
- num = q->num;
- num.sign = 0;
- if (zrel(num, q->den) >= 0)
- math_error("Leg too large in legtoleg");
- qtmp1 = qsquare(q);
- qtmp2 = qsub(&_qone_, qtmp1);
- qfree(qtmp1);
- res = qsqrt(qtmp2, epsilon);
- qfree(qtmp2);
- if (wantneg) {
- qtmp1 = qneg(res);
- qfree(res);
- res = qtmp1;
- }
- return res;
- }
-
- /*
- * Compute the square root of a number to within the specified error.
- * If the number is an exact square, the exact result is returned.
- * q3 = qsqrt(q1, q2);
- */
- NUMBER *
- qsqrt(q1, epsilon)
- register NUMBER *q1, *epsilon;
- {
- long bits, bits2; /* number of bits of precision */
- int exact;
- NUMBER *r;
- ZVALUE t1, t2;
-
- if (qisneg(q1))
- math_error("Square root of negative number");
- if (qisneg(epsilon) || qiszero(epsilon))
- math_error("Bad epsilon value for sqrt");
- if (qiszero(q1))
- return qlink(&_qzero_);
- if (qisunit(q1))
- return qlink(&_qone_);
- if (qiszero(epsilon) && qisint(q1) && zistiny(q1->num) && (*q1->num.v <= 3))
- return qlink(&_qone_);
- bits = zhighbit(epsilon->den) - zhighbit(epsilon->num) + 1;
- if (bits < 0)
- bits = 0;
- bits2 = zhighbit(q1->num) - zhighbit(q1->den) + 1;
- if (bits2 > 0)
- bits += bits2;
- r = qalloc();
- zshift(q1->num, bits * 2, &t2);
- zmul(q1->den, t2, &t1);
- zfree(t2);
- exact = zsqrt(t1, &t2);
- zfree(t1);
- if (exact) {
- zshift(q1->den, bits, &t1);
- zreduce(t2, t1, &r->num, &r->den);
- } else {
- zquo(t2, q1->den, &t1);
- zfree(t2);
- zbitvalue(bits, &t2);
- zreduce(t1, t2, &r->num, &r->den);
- }
- zfree(t1);
- zfree(t2);
- if (qiszero(r)) {
- qfree(r);
- r = qlink(&_qzero_);
- }
- return r;
- }
-
-
- /*
- * Calculate the integral part of the square root of a number.
- * Example: qisqrt(13) = 3.
- */
- NUMBER *
- qisqrt(q)
- NUMBER *q;
- {
- NUMBER *r;
- ZVALUE tmp;
-
- if (qisneg(q))
- math_error("Square root of negative number");
- if (qiszero(q))
- return qlink(&_qzero_);
- if (qisint(q) && zistiny(q->num) && (z1tol(q->num) < 4))
- return qlink(&_qone_);
- r = qalloc();
- if (qisint(q)) {
- (void) zsqrt(q->num, &r->num);
- return r;
- }
- zquo(q->num, q->den, &tmp);
- (void) zsqrt(tmp, &r->num);
- zfree(tmp);
- return r;
- }
-
-
- /*
- * Return whether or not a number is an exact square.
- */
- BOOL
- qissquare(q)
- NUMBER *q;
- {
- BOOL flag;
-
- flag = zissquare(q->num);
- if (qisint(q) || !flag)
- return flag;
- return zissquare(q->den);
- }
-
-
- /*
- * Compute the greatest integer of the Kth root of a number.
- * Example: qiroot(85, 3) = 4.
- */
- NUMBER *
- qiroot(q1, q2)
- register NUMBER *q1, *q2;
- {
- NUMBER *r;
- ZVALUE tmp;
-
- if (qisneg(q2) || qiszero(q2) || qisfrac(q2))
- math_error("Taking number to bad root value");
- if (qiszero(q1))
- return qlink(&_qzero_);
- if (qisone(q1) || qisone(q2))
- return qlink(q1);
- if (qistwo(q2))
- return qisqrt(q1);
- r = qalloc();
- if (qisint(q1)) {
- zroot(q1->num, q2->num, &r->num);
- return r;
- }
- zquo(q1->num, q1->den, &tmp);
- zroot(tmp, q2->num, &r->num);
- zfree(tmp);
- return r;
- }
-
-
- /*
- * Return the greatest integer of the base 2 log of a number.
- * This is the number such that 1 <= x / log2(x) < 2.
- * Examples: qilog2(8) = 3, qilog2(1.3) = 1, qilog2(1/7) = -3.
- */
- long
- qilog2(q)
- NUMBER *q; /* number to take log of */
- {
- long n; /* power of two */
- int c; /* result of comparison */
- ZVALUE tmp; /* temporary value */
-
- if (qisneg(q) || qiszero(q))
- math_error("Non-positive number for log2");
- if (qisint(q))
- return zhighbit(q->num);
- n = zhighbit(q->num) - zhighbit(q->den);
- if (n == 0)
- c = zrel(q->num, q->den);
- else if (n > 0) {
- zshift(q->den, n, &tmp);
- c = zrel(q->num, tmp);
- } else {
- zshift(q->num, -n, &tmp);
- c = zrel(tmp, q->den);
- }
- if (n)
- zfree(tmp);
- if (c < 0)
- n--;
- return n;
- }
-
-
- /*
- * Return the greatest integer of the base 10 log of a number.
- * This is the number such that 1 <= x / log10(x) < 10.
- * Examples: qilog10(100) = 2, qilog10(12.3) = 1, qilog10(.023) = -2.
- */
- long
- qilog10(q)
- NUMBER *q; /* number to take log of */
- {
- long n; /* log value */
- ZVALUE temp; /* temporary value */
-
- if (qisneg(q) || qiszero(q))
- math_error("Non-positive number for log10");
- if (qisint(q))
- return zlog10(q->num);
- /*
- * The number is not an integer.
- * Compute the result if the number is greater than one.
- */
- if ((q->num.len > q->den.len) ||
- ((q->num.len == q->den.len) && (zrel(q->num, q->den) > 0))) {
- zquo(q->num, q->den, &temp);
- n = zlog10(temp);
- zfree(temp);
- return n;
- }
- /*
- * Here if the number is less than one.
- * If the number is the inverse of a power of ten, then the obvious answer
- * will be off by one. Subtracting one if the number is the inverse of an
- * integer will fix it.
- */
- if (zisunit(q->num))
- zsub(q->den, _one_, &temp);
- else
- zquo(q->den, q->num, &temp);
- n = -zlog10(temp) - 1;
- zfree(temp);
- return n;
- }
-
-
- /*
- * Return the number of digits in a number, ignoring the sign.
- * For fractions, this is the number of digits of its greatest integer.
- * Examples: qdigits(3456) = 4, qdigits(-23.45) = 2, qdigits(.0120) = 1.
- */
- long
- qdigits(q)
- NUMBER *q; /* number to count digits of */
- {
- long n; /* number of digits */
- ZVALUE temp; /* temporary value */
-
- if (qisint(q))
- return zdigits(q->num);
- zquo(q->num, q->den, &temp);
- n = zdigits(temp);
- zfree(temp);
- return n;
- }
-
-
- /*
- * Return the digit at the specified decimal place of a number represented
- * in floating point. The lowest digit of the integral part of a number
- * is the zeroth decimal place. Negative decimal places indicate digits
- * to the right of the decimal point. Examples: qdigit(1234.5678, 1) = 3,
- * qdigit(1234.5678, -3) = 7.
- */
- FLAG
- qdigit(q, n)
- NUMBER *q;
- long n;
- {
- ZVALUE tenpow, tmp1, tmp2;
- FLAG res;
-
- /*
- * Zero number or negative decimal place of integer is trivial.
- */
- if (qiszero(q) || (qisint(q) && (n < 0)))
- return 0;
- /*
- * For non-negative decimal places, answer is easy.
- */
- if (n >= 0) {
- if (qisint(q))
- return zdigit(q->num, n);
- zquo(q->num, q->den, &tmp1);
- res = zdigit(tmp1, n);
- zfree(tmp1);
- return res;
- }
- /*
- * Fractional value and want negative digit, must work harder.
- */
- ztenpow(-n, &tenpow);
- zmul(q->num, tenpow, &tmp1);
- zfree(tenpow);
- zquo(tmp1, q->den, &tmp2);
- res = zmodi(tmp2, 10L);
- zfree(tmp1);
- zfree(tmp2);
- return res;
- }
-
-
- /*
- * Return whether or not a bit is set at the specified bit position in a
- * number. The lowest bit of the integral part of a number is the zeroth
- * bit position. Negative bit positions indicate bits to the right of the
- * binary decimal point. Examples: qdigit(17.1, 0) = 1, qdigit(17.1, -1) = 0.
- */
- BOOL
- qisset(q, n)
- NUMBER *q;
- long n;
- {
- NUMBER *qtmp1, *qtmp2;
- ZVALUE ztmp;
- BOOL res;
-
- /*
- * Zero number or negative bit position place of integer is trivial.
- */
- if (qiszero(q) || (qisint(q) && (n < 0)))
- return FALSE;
- /*
- * For non-negative bit positions, answer is easy.
- */
- if (n >= 0) {
- if (qisint(q))
- return zisset(q->num, n);
- zquo(q->num, q->den, &ztmp);
- res = zisset(ztmp, n);
- zfree(ztmp);
- return res;
- }
- /*
- * Fractional value and want negative bit position, must work harder.
- */
- qtmp1 = qscale(q, -n);
- qtmp2 = qint(qtmp1);
- qfree(qtmp1);
- res = ((qtmp2->num.v[0] & 0x01) != 0);
- qfree(qtmp2);
- return res;
- }
-
-
- /*
- * Compute the factorial of an integer.
- * q2 = qfact(q1);
- */
- NUMBER *
- qfact(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qisfrac(q))
- math_error("Non-integral factorial");
- if (qiszero(q) || zisone(q->num))
- return qlink(&_qone_);
- r = qalloc();
- zfact(q->num, &r->num);
- return r;
- }
-
-
- /*
- * Compute the product of the primes less than or equal to a number.
- * q2 = qpfact(q1);
- */
- NUMBER *
- qpfact(q)
- register NUMBER *q;
- {
- NUMBER *r;
-
- if (qisfrac(q))
- math_error("Non-integral factorial");
- r = qalloc();
- zpfact(q->num, &r->num);
- return r;
- }
-
-
- /*
- * Compute the lcm of all the numbers less than or equal to a number.
- * q2 = qlcmfact(q1);
- */
- NUMBER *
- qlcmfact(q)
- register NUMBER *q;
- {
- NUMBER *r;
-
- if (qisfrac(q))
- math_error("Non-integral lcmfact");
- r = qalloc();
- zlcmfact(q->num, &r->num);
- return r;
- }
-
-
- /*
- * Compute the permutation function M! / (M - N)!.
- */
- NUMBER *
- qperm(q1, q2)
- register NUMBER *q1, *q2;
- {
- register NUMBER *r;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integral arguments for permutation");
- r = qalloc();
- zperm(q1->num, q2->num, &r->num);
- return r;
- }
-
-
- /*
- * Compute the combinatorial function M! / (N! * (M - N)!).
- */
- NUMBER *
- qcomb(q1, q2)
- register NUMBER *q1, *q2;
- {
- register NUMBER *r;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integral arguments for combinatorial");
- r = qalloc();
- zcomb(q1->num, q2->num, &r->num);
- return r;
- }
-
-
- /*
- * Compute the Jacobi function (a / b).
- * -1 => a is not quadratic residue mod b
- * 1 => b is composite, or a is quad residue of b
- * 0 => b is even or b < 0
- */
- NUMBER *
- qjacobi(q1, q2)
- register NUMBER *q1, *q2;
- {
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integral arguments for jacobi");
- return itoq((long) zjacobi(q1->num, q2->num));
- }
-
-
- /*
- * Compute the Fibonacci number F(n).
- */
- NUMBER *
- qfib(q)
- register NUMBER *q;
- {
- register NUMBER *r;
-
- if (qisfrac(q))
- math_error("Non-integral Fibonacci number");
- r = qalloc();
- zfib(q->num, &r->num);
- return r;
- }
-
-
- /*
- * Truncate a number to the specified number of decimal places.
- * Specifying zero places makes the result identical to qint.
- * Example: qtrunc(2/3, 3) = .666
- */
- NUMBER *
- qtrunc(q1, q2)
- NUMBER *q1, *q2;
- {
- long places;
- NUMBER *r;
- ZVALUE tenpow, tmp1, tmp2;
-
- if (qisfrac(q2) || qisneg(q2) || !zistiny(q2->num))
- math_error("Bad number of places for qtrunc");
- if (qisint(q1))
- return qlink(q1);
- r = qalloc();
- places = z1tol(q2->num);
- /*
- * Ok, produce the result.
- * First see if we want no places, in which case just take integer part.
- */
- if (places == 0) {
- zquo(q1->num, q1->den, &r->num);
- return r;
- }
- ztenpow(places, &tenpow);
- zmul(q1->num, tenpow, &tmp1);
- zquo(tmp1, q1->den, &tmp2);
- zfree(tmp1);
- if (ziszero(tmp2)) {
- zfree(tmp2);
- return qlink(&_qzero_);
- }
- /*
- * Now reduce the result to the lowest common denominator.
- */
- zgcd(tmp2, tenpow, &tmp1);
- if (zisunit(tmp1)) {
- zfree(tmp1);
- r->num = tmp2;
- r->den = tenpow;
- return r;
- }
- zquo(tmp2, tmp1, &r->num);
- zquo(tenpow, tmp1, &r->den);
- zfree(tmp1);
- zfree(tmp2);
- zfree(tenpow);
- return r;
- }
-
-
- /*
- * Round a number to the specified number of decimal places.
- * Zero decimal places means round to the nearest integer.
- * Example: qround(2/3, 3) = .667
- */
- NUMBER *
- qround(q, places)
- NUMBER *q; /* number to be rounded */
- long places; /* number of decimal places to round to */
- {
- NUMBER *r;
- ZVALUE tenpow, roundval, tmp1, tmp2;
-
- if (places < 0)
- math_error("Negative places for qround");
- if (qisint(q))
- return qlink(q);
- /*
- * Calculate one half of the denominator, ignoring fractional results.
- * This is the value we will add in order to cause rounding.
- */
- zshift(q->den, -1L, &roundval);
- roundval.sign = q->num.sign;
- /*
- * Ok, now do the actual work to produce the result.
- */
- r = qalloc();
- ztenpow(places, &tenpow);
- zmul(q->num, tenpow, &tmp2);
- zadd(tmp2, roundval, &tmp1);
- zfree(tmp2);
- zfree(roundval);
- zquo(tmp1, q->den, &tmp2);
- zfree(tmp1);
- if (ziszero(tmp2)) {
- zfree(tmp2);
- return qlink(&_qzero_);
- }
- /*
- * Now reduce the result to the lowest common denominator.
- */
- zgcd(tmp2, tenpow, &tmp1);
- if (zisunit(tmp1)) {
- zfree(tmp1);
- r->num = tmp2;
- r->den = tenpow;
- return r;
- }
- zquo(tmp2, tmp1, &r->num);
- zquo(tenpow, tmp1, &r->den);
- zfree(tmp1);
- zfree(tmp2);
- zfree(tenpow);
- return r;
- }
-
-
- /*
- * Truncate a number to the specified number of binary places.
- * Specifying zero places makes the result identical to qint.
- */
- NUMBER *
- qbtrunc(q1, q2)
- NUMBER *q1, *q2;
- {
- long places, twopow;
- NUMBER *r;
- ZVALUE tmp1, tmp2;
-
- if (qisfrac(q2) || qisneg(q2) || !zistiny(q2->num))
- math_error("Bad number of places for qtrunc");
- if (qisint(q1))
- return qlink(q1);
- r = qalloc();
- places = z1tol(q2->num);
- /*
- * Ok, produce the result.
- * First see if we want no places, in which case just take integer part.
- */
- if (places == 0) {
- zquo(q1->num, q1->den, &r->num);
- return r;
- }
- zshift(q1->num, places, &tmp1);
- zquo(tmp1, q1->den, &tmp2);
- zfree(tmp1);
- if (ziszero(tmp2)) {
- zfree(tmp2);
- return qlink(&_qzero_);
- }
- /*
- * Now reduce the result to the lowest common denominator.
- */
- if (zisodd(tmp2)) {
- r->num = tmp2;
- zbitvalue(places, &r->den);
- return r;
- }
- twopow = zlowbit(tmp2);
- if (twopow > places)
- twopow = places;
- places -= twopow;
- zshift(tmp2, -twopow, &r->num);
- zfree(tmp2);
- zbitvalue(places, &r->den);
- return r;
- }
-
-
- /*
- * Round a number to the specified number of binary places.
- * Zero binary places means round to the nearest integer.
- */
- NUMBER *
- qbround(q, places)
- NUMBER *q; /* number to be rounded */
- long places; /* number of binary places to round to */
- {
- long twopow;
- NUMBER *r;
- ZVALUE roundval, tmp1, tmp2;
-
- if (places < 0)
- math_error("Negative places for qbround");
- if (qisint(q))
- return qlink(q);
- r = qalloc();
- /*
- * Calculate one half of the denominator, ignoring fractional results.
- * This is the value we will add in order to cause rounding.
- */
- zshift(q->den, -1L, &roundval);
- roundval.sign = q->num.sign;
- /*
- * Ok, produce the result.
- */
- zshift(q->num, places, &tmp1);
- zadd(tmp1, roundval, &tmp2);
- zfree(roundval);
- zfree(tmp1);
- zquo(tmp2, q->den, &tmp1);
- zfree(tmp2);
- if (ziszero(tmp1)) {
- zfree(tmp1);
- return qlink(&_qzero_);
- }
- /*
- * Now reduce the result to the lowest common denominator.
- */
- if (zisodd(tmp1)) {
- r->num = tmp1;
- zbitvalue(places, &r->den);
- return r;
- }
- twopow = zlowbit(tmp1);
- if (twopow > places)
- twopow = places;
- places -= twopow;
- zshift(tmp1, -twopow, &r->num);
- zfree(tmp1);
- zbitvalue(places, &r->den);
- return r;
- }
-
-
- /*
- * Approximate a number by using binary rounding with the minimum number
- * of binary places so that the resulting number differs from the
- * original number by no more than epsilon/2.
- */
-
- NUMBER *
- qbappr(q, e)
- NUMBER *q, *e;
- {
- long bits;
-
- if (qiszero(e))
- return qlink(q);
- if (qisneg(e))
- math_error("Bad epsilon value for qbappr");
- if (e == _epsilon_)
- bits = _epsilonprec_;
- else
- bits = qprecision(e);
- return qbround(q, bits);
- }
-
-
- /*
- * Approximate a number using continued fractions until the approximation
- * error is less than the specified value. If a NULL pointer is given
- * for the error value, then the closest simpler fraction is returned.
- */
- NUMBER *
- qcfappr(q, e)
- NUMBER *q, *e;
- {
- NUMBER qtest, *qtmp;
- ZVALUE u1, u2, u3, v1, v2, v3, t1, t2, t3, qq, tt;
- int i;
- BOOL haveeps;
-
- haveeps = TRUE;
- if (e == NULL) {
- haveeps = FALSE;
- e = &_qzero_;
- }
- if (qisneg(e))
- math_error("Negative epsilon for cfappr");
- if (qisint(q) || zisunit(q->num) || (haveeps && qiszero(e)))
- return qlink(q);
- u1 = _one_;
- u2 = _zero_;
- u3 = q->num;
- u3.sign = 0;
- v1 = _zero_;
- v2 = _one_;
- v3 = q->den;
- while (!ziszero(v3)) {
- if (!ziszero(u2) && !ziszero(u1)) {
- qtest.num = u2;
- qtest.den = u1;
- qtest.den.sign = 0;
- qtest.num.sign = q->num.sign;
- qtmp = qsub(q, &qtest);
- qtest = *qtmp;
- qtest.num.sign = 0;
- i = qrel(&qtest, e);
- qfree(qtmp);
- if (i <= 0)
- break;
- }
- zquo(u3, v3, &qq);
- zmul(qq, v1, &tt); zsub(u1, tt, &t1); zfree(tt);
- zmul(qq, v2, &tt); zsub(u2, tt, &t2); zfree(tt);
- zmul(qq, v3, &tt); zsub(u3, tt, &t3); zfree(tt);
- zfree(qq); zfree(u1); zfree(u2);
- if ((u3.v != q->num.v) && (u3.v != q->den.v))
- zfree(u3);
- u1 = v1; u2 = v2; u3 = v3;
- v1 = t1; v2 = t2; v3 = t3;
- }
- if (u3.v != q->den.v)
- zfree(u3);
- zfree(v1);
- zfree(v2);
- i = ziszero(v3);
- zfree(v3);
- if (i && haveeps) {
- zfree(u1);
- zfree(u2);
- return qlink(q);
- }
- qtest.num = u2;
- qtest.den = u1;
- qtest.den.sign = 0;
- qtest.num.sign = q->num.sign;
- qtmp = qcopy(&qtest);
- zfree(u1);
- zfree(u2);
- return qtmp;
- }
-
-
- /*
- * Return an indication on whether or not two fractions are approximately
- * equal within the specified epsilon. Returns negative if the absolute value
- * of the difference between the two numbers is less than epsilon, zero if
- * the difference is equal to epsilon, and positive if the difference is
- * greater than epsilon.
- */
- FLAG
- qnear(q1, q2, epsilon)
- NUMBER *q1, *q2, *epsilon;
- {
- int res;
- NUMBER qtemp, *qq;
-
- if (qisneg(epsilon))
- math_error("Negative epsilon for near");
- if (q1 == q2) {
- if (qiszero(epsilon))
- return 0;
- return -1;
- }
- if (qiszero(epsilon))
- return qcmp(q1, q2);
- if (qiszero(q2)) {
- qtemp = *q1;
- qtemp.num.sign = 0;
- return qrel(&qtemp, epsilon);
- }
- if (qiszero(q1)) {
- qtemp = *q2;
- qtemp.num.sign = 0;
- return qrel(&qtemp, epsilon);
- }
- qq = qsub(q1, q2);
- qtemp = *qq;
- qtemp.num.sign = 0;
- res = qrel(&qtemp, epsilon);
- qfree(qq);
- return res;
- }
-
-
- /*
- * Compute the gcd (greatest common divisor) of two numbers.
- * q3 = qgcd(q1, q2);
- */
- NUMBER *
- qgcd(q1, q2)
- register NUMBER *q1, *q2;
- {
- ZVALUE z;
- NUMBER *q;
-
- if (q1 == q2)
- return qabs(q1);
- if (qisfrac(q1) || qisfrac(q2)) {
- q = qalloc();
- zgcd(q1->num, q2->num, &q->num);
- zlcm(q1->den, q2->den, &q->den);
- return q;
- }
- if (qiszero(q1))
- return qabs(q2);
- if (qiszero(q2))
- return qabs(q1);
- if (qisunit(q1) || qisunit(q2))
- return qlink(&_qone_);
- zgcd(q1->num, q2->num, &z);
- if (zisunit(z)) {
- zfree(z);
- return qlink(&_qone_);
- }
- q = qalloc();
- q->num = z;
- return q;
- }
-
-
- /*
- * Compute the lcm (least common multiple) of two numbers.
- * q3 = qlcm(q1, q2);
- */
- NUMBER *
- qlcm(q1, q2)
- register NUMBER *q1, *q2;
- {
- NUMBER *q;
-
- if (qiszero(q1) || qiszero(q2))
- return qlink(&_qzero_);
- if (q1 == q2)
- return qabs(q1);
- if (qisunit(q1))
- return qabs(q2);
- if (qisunit(q2))
- return qabs(q1);
- q = qalloc();
- zlcm(q1->num, q2->num, &q->num);
- if (qisfrac(q1) || qisfrac(q2))
- zgcd(q1->den, q2->den, &q->den);
- return q;
- }
-
-
- /*
- * Remove all occurances of the specified factor from a number.
- * Returned number is always positive.
- */
- NUMBER *
- qfacrem(q1, q2)
- NUMBER *q1, *q2;
- {
- long count;
- ZVALUE tmp;
- NUMBER *r;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for factor removal");
- count = zfacrem(q1->num, q2->num, &tmp);
- if (zisunit(tmp)) {
- zfree(tmp);
- return qlink(&_qone_);
- }
- if (count == 0) {
- zfree(tmp);
- return qlink(q1);
- }
- r = qalloc();
- r->num = tmp;
- return r;
- }
-
-
- /*
- * Divide one number by the gcd of it with another number repeatedly until
- * the number is relatively prime.
- */
- NUMBER *
- qgcdrem(q1, q2)
- NUMBER *q1, *q2;
- {
- ZVALUE tmp;
- NUMBER *r;
-
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for gcdrem");
- zgcdrem(q1->num, q2->num, &tmp);
- if (zisunit(tmp)) {
- zfree(tmp);
- return qlink(&_qone_);
- }
- if (zcmp(q1->num, tmp) == 0) {
- zfree(tmp);
- return qlink(q1);
- }
- r = qalloc();
- r->num = tmp;
- return r;
- }
-
-
- /*
- * Return the lowest prime factor of a number.
- * Search is conducted for the specified number of primes.
- * Returns one if no factor was found.
- */
- NUMBER *
- qlowfactor(q1, q2)
- NUMBER *q1, *q2;
- {
- if (qisfrac(q1) || qisfrac(q2))
- math_error("Non-integers for lowfactor");
- return itoq(zlowfactor(q1->num, ztoi(q2->num)));
- }
-
-
- /*
- * Return the number of places after the decimal point needed to exactly
- * represent the specified number as a real number. Integers return zero,
- * and non-terminating decimals return minus one. Examples:
- * qplaces(1/7)=-1, qplaces(3/10)= 1, qplaces(1/8)=3, qplaces(4)=0.
- */
- long
- qplaces(q)
- NUMBER *q;
- {
- long twopow, fivepow;
- HALF fiveval[2];
- ZVALUE five;
- ZVALUE tmp;
-
- if (qisint(q)) /* no decimal places if number is integer */
- return 0;
- /*
- * The number of decimal places of a fraction in lowest terms is finite
- * if an only if the denominator is of the form 2^A * 5^B, and then the
- * number of decimal places is equal to MAX(A, B).
- */
- five.sign = 0;
- five.len = 1;
- five.v = fiveval;
- fiveval[0] = 5;
- fivepow = zfacrem(q->den, five, &tmp);
- if (!zisonebit(tmp)) {
- zfree(tmp);
- return -1;
- }
- twopow = zlowbit(tmp);
- zfree(tmp);
- if (twopow < fivepow)
- twopow = fivepow;
- return twopow;
- }
-
-
- /*
- * Perform a probabilistic primality test (algorithm P in Knuth).
- * Returns FALSE if definitely not prime, or TRUE if probably prime.
- * Second arg determines how many times to check for primality.
- */
- BOOL
- qprimetest(q1, q2)
- NUMBER *q1, *q2;
- {
- if (qisfrac(q1) || qisfrac(q2) || qisneg(q2))
- math_error("Bad arguments for qprimetest");
- return zprimetest(q1->num, qtoi(q2));
- }
-
-
- /*
- * Return a trivial hash value for a number.
- */
- HASH
- qhash(q)
- NUMBER *q;
- {
- HASH hash;
-
- hash = zhash(q->num);
- if (qisfrac(q))
- hash += zhash(q->den) * 2000003;
- return hash;
- }
-
- /* END CODE */
-